package rad.framework.mda.jpagen.actions;

import rad.framework.mda.generator.Console;
import rad.framework.mda.generator.util.StereotypeHelper;
import rad.framework.mda.util.ModelUtil;

import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.impl.DynamicEObjectImpl;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.uml2.uml.Association;
import org.eclipse.uml2.uml.Class;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.Stereotype;

/**
 * @author boudyacho
 * 
 */
public class AddJoinTableActionExtension extends BaseUtiltiyActionExtension {

	protected static final String JOIN_TABLE = "javax.persistence.JoinTable";

	public void fillContextMenu(IMenuManager aMenu) {
		getSubMenu(aMenu).add(new AddJoinTableAction());
	}

	protected void execute(Class clazz) {
		if (StereotypeHelper
				.isStereotypeApplied(clazz, StereotypeHelper.ENTITY)) {
			EList<NamedElement> list = clazz.getMembers();
			for (NamedElement namedElement : list) {
				if (namedElement instanceof Property) {
					execute((Property) namedElement);
				}
			}
		}
	}

	protected void execute(Property property) {
		if (ModelUtil.isStereotypeApplied(property, M2M)) {
			if (isUnidirectional(property) && isSource(property)) {
				applyJoinTable((NamedElement) property.getOwner(), getSource(property), property, getTarget(property), getSource(property));
				// undo previous
				unapplyJoinTable(getTarget(property));
				Console.getStream().println(
						"Added " + JOIN_TABLE + " - "
								+ property.getQualifiedName());
			} else if (!isUnidirectional(property) && !isSource(property)) {
				// TODO this is probably backwards, same for cleanup m2m
				applyJoinTable((NamedElement) getSource(property).getOwner(), getSource(property), property, getSource(property), getTarget(property));
				// undo previous
				unapplyJoinTable(getSource(property));
				Console.getStream().println(
						"Added " + JOIN_TABLE + " - "
								+ property.getQualifiedName());
			}
		}
	}

	private boolean isUnidirectional(Property element) {
		return element.isNavigable() && element.getOpposite() == null;
	}
	
	protected Property getSource(Property p) {
		Association a = p.getAssociation();
		return a.getMemberEnds().get(0);
	}
	
	protected Property getTarget(Property p) {
		Association a = p.getAssociation();
		return a.getMemberEnds().get(1);
	}
	
	private void applyJoinTable(NamedElement master, Property target, Property element, Property join, Property inverse) {
		Stereotype stereotype = (Stereotype) ModelUtil.getProfileElement(
				element, JOIN_TABLE);
		if (stereotype != null) {
			if (ModelUtil.isStereotypeApplied(element, JOIN_TABLE)) {
				element.unapplyStereotype(stereotype);
			}
			EObject application = element.applyStereotype(stereotype);

			String name = NameUtil.getAbbreviation(master)
					+ "_" + NameUtil.getAbbreviation(target);
			checkLength(element, name, 21);
			element.setValue(stereotype, "name", name);

			DynamicEObjectImpl joinColumns = createChild(application);
			addChild(application, joinColumns, "joinColumns");

			name = NameUtil.getAbbreviation(join) + "_ID";
			checkLength(join, name, 26);
			setAttribute(joinColumns, "name", name);

			DynamicEObjectImpl inverseJoinColumns = createChild(application);
			addChild(application, inverseJoinColumns, "inverseJoinColumns");

			name = NameUtil.getAbbreviation(inverse) + "_ID";
			checkLength(element, name, 26);
			setAttribute(inverseJoinColumns, "name", name);
		}
	}

	private void unapplyJoinTable(Property element) {
		Stereotype stereotype = (Stereotype) ModelUtil.getProfileElement(
				element, JOIN_TABLE);
		if (stereotype != null) {
			if (ModelUtil.isStereotypeApplied(element, JOIN_TABLE)) {
				element.unapplyStereotype(stereotype);
			}
		}
	}

	private class AddJoinTableAction extends BaseUtilityAction {
		private static final String LABEL = "Add Join Table Stereotypes";

		public AddJoinTableAction() {
			super(LABEL);
		}
	}
}
